﻿
Imports System.Text
Imports System.Runtime.CompilerServices
Imports osi.root.constants

Public Module _strcat
    Private Delegate Function strcatDelegate(ByRef dest As String, ByVal src As String) As String
    Private Function strncatImpl(ByRef dest As String, ByVal src As String, ByVal count As Int64,
                                 ByVal impl As strcatDelegate) As String
        Dim len As Int64 = 0
        len = strlen(src)
        If len > 1 Then
            While count > 0
                impl(dest, src)
                count -= 1
            End While
        Else
            impl(dest, New String(src(0), count))
        End If
        Return dest
    End Function

    'the binding of strcat will be changed
    Public Function strcat(ByRef dest As String, ByVal src As String) As String
        dest += src
        Return dest
    End Function

    <Extension()> Public Function strrcat(ByRef dest As String, ByVal src As String) As String
        dest = src + dest
        Return dest
    End Function

    <Extension()> Public Function strncat(ByRef dest As String, ByVal src As String, ByVal count As Int64) As String
        Return strncatImpl(dest, src, count, AddressOf strcat)
    End Function

    <Extension()> Public Function strrncat(ByRef dest As String, ByVal src As String, ByVal count As Int64) As String
        Return strncatImpl(dest, src, count, AddressOf strrcat)
    End Function

    Private Delegate Function strncatDelegate(ByRef dest As String,
                                              ByVal src As String,
                                              ByVal count As Int64) As String
    Private Function strfillImpl(ByRef dest As String, ByVal src As String, ByVal length As Int64, _
                                 ByVal impl As strncatDelegate) As String
        Dim required_times As Int64 = 0
        required_times = length - strlen(dest)
        If required_times <> 0 Then
            Dim srclen As Int64 = 0
            srclen = strlen(src)
            k_assert(srclen > 0, "src is nothing or emptystring, cannot fill to required length.")
            k_assert(required_times >= 0, "dest length is already over length.")
            k_assert(required_times / srclen = required_times \ srclen, "requiredTimes is not an integer.")
            required_times /= srclen
            impl(dest, src, required_times)
        End If
        Return dest
    End Function

    <Extension()> Public Function strfill(ByRef dest As String, ByVal src As String, ByVal length As Int64) As String
        Return strfillImpl(dest, src, length, AddressOf strncat)
    End Function

    <Extension()> Public Function strrfill(ByRef dest As String, ByVal src As String, ByVal length As Int64) As String
        Return strfillImpl(dest, src, length, AddressOf strrncat)
    End Function

    Public Function strcat(ByVal ParamArray p() As Object) As String
        Dim s As StringBuilder = Nothing
        If Not p Is Nothing AndAlso p.Length() > 0 Then
            s = New StringBuilder()
            For i As Int32 = 0 To p.Length() - 1
                s.Append(Convert.ToString(p(i)))
            Next
        End If
        Return Convert.ToString(s)
    End Function

    Public Function strcat(Of T)(ByVal ParamArray p() As T) As String
        Dim s As StringBuilder = Nothing
        If Not isemptyarray(p) Then
            s = New StringBuilder()
            For i As Int32 = 0 To p.Length() - 1
                s.Append(p(i))
            Next
        End If
        Return Convert.ToString(s)
    End Function

    Public Function strcat(ByVal ParamArray p() As String) As String
        Dim s As StringBuilder = Nothing
        If Not isemptyarray(p) Then
            s = New StringBuilder()
            For i As Int32 = 0 To p.Length() - 1
                s.Append(p(i))
            Next
        End If
        Return Convert.ToString(s)
    End Function

    Public Function strcat(ByVal ParamArray p() As Char) As String
        Dim s As StringBuilder = Nothing
        If Not isemptyarray(p) Then
            s = New StringBuilder()
            For i As Int32 = 0 To p.Length() - 1
                s.Append(p(i))
            Next
        End If
        Return Convert.ToString(s)
    End Function

    <Extension()> Public Function append(ByRef this As String, ByVal ParamArray p() As Object) As String
        Dim s As String = Nothing
        s = strcat(p)
        Return strcat(this, s)
    End Function

    <Extension()> Public Function strjoin(ByVal vs() As String,
                                          ByVal sep As String,
                                          ByVal start As Int32,
                                          ByVal count As Int32) As String
        Return strjoin(sep, vs, start, count)
    End Function

    <Extension()> Public Function strjoin(ByVal vs() As String,
                                          ByVal sep As String,
                                          ByVal start As Int32) As String
        Return strjoin(sep, vs, start)
    End Function

    <Extension()> Public Function strjoin(ByVal vs() As String,
                                          ByVal sep As String) As String
        Return strjoin(sep, vs)
    End Function

    Public Function strjoin(ByVal sep As String,
                            ByVal vs() As String,
                            ByVal start As Int32,
                            ByVal count As Int32) As String
        If start < 0 OrElse count < 0 OrElse isemptyarray(vs) Then
            Return Nothing
        Else
            count = min(count, array_size(vs) - start)
            Return String.Join(sep, vs, start, count)
        End If
    End Function

    Public Function strjoin(ByVal sep As String,
                            ByVal vs() As String,
                            ByVal start As Int32) As String
        Return strjoin(sep, vs, start, max_int32)
    End Function

    Public Function strjoin(ByVal sep As String, ByVal ParamArray vs() As String) As String
        Return strjoin(sep, vs, 0, array_size(vs))
    End Function
End Module
